#include "window.h"
#include "defines/methods.h"
#include "sphereDialog.h"
#include "fabricDialog.h"
#include "particlesDialog.h"
#include "particleDialog.h"
#include "springsDialog.h"
#include "springDialog.h"
#include "fabricTreeItem.h"
#include "objectTreeItem.h"
#include "src/improvedVerlet.h"
#include "src/implicitSOR.h"
#include "src/implicitJacobi.h"
#include "globalOptionsPanel.h"
#include "collisionOptionsPanel.h"
#include "airOptionsPanel.h"
#include "methodsOptionsPanel.h"

#include <QFile>

Window::Window()
{
    method = FORWARD_EULER;
    objectId = 0;
    objectInOperation = false;
    fabricInOperation = false;

    fileName = QString();
    playbackFileName = QString();
    glWidget = new GLWidget;
    setCentralWidget(glWidget);

    statusBar()->showMessage(tr(""));

    createActionsMenusToolbar();

    setWindowTitle(tr("Cloth Animation"));



    connect(glWidget->getInput(), SIGNAL(playbackEnded()), this, SLOT(stopSimulation()));
}

Window::~Window(){
    if(glWidget) delete glWidget;
}

void Window::createActionsMenusToolbar(){

    //Criando paineis ----------------------------------------------------------

    QDockWidget *fabricTreePanelDock = new QDockWidget(tr("Tecidos"), this);

    fabricTree = new QTreeWidget(fabricTreePanelDock);
    fabricTree->setHeaderHidden(true);
    fabricTree->setContextMenuPolicy(Qt::ActionsContextMenu);
    fabricTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
    fabricTree->setSelectionBehavior(QAbstractItemView::SelectRows);
    fabricTree->setAnimated(true);
    fabricTree->setExpandsOnDoubleClick(false);

    fabricTreePanelDock->setWidget(fabricTree);
    fabricTreePanelDock->setMaximumWidth(350);
    addDockWidget(Qt::RightDockWidgetArea, fabricTreePanelDock);

    QAction *viewFabricTreePanelAct = fabricTreePanelDock->toggleViewAction();

    deleteFabricAct = new QAction(QString::fromUtf8("Deletar tecido"), this);
    deleteFabricAct->setShortcuts(QKeySequence::Delete);
    deleteFabricAct->setEnabled(false);
    deleteFabricAct->setStatusTip(QString::fromUtf8("Deletar tecidos selecionados."));
    connect(deleteFabricAct, SIGNAL(triggered()), this, SLOT(deleteFabric()));

    fabricTree->addAction(deleteFabricAct);

    connect(fabricTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(editFabricDialog(QTreeWidgetItem *, int)));
    connect(fabricTree, SIGNAL(itemSelectionChanged()), this, SLOT(changeFabricsSelection()));


    QDockWidget *objectTreePanelDock = new QDockWidget(tr("Objetos"), this);

    objectTree = new QTreeWidget(objectTreePanelDock);
    objectTree->setHeaderHidden(true);
    objectTree->setContextMenuPolicy(Qt::ActionsContextMenu);
    objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
    objectTree->setSelectionBehavior(QAbstractItemView::SelectRows);
    objectTree->setAnimated(true);
    objectTree->setExpandsOnDoubleClick(false);

    objectTreePanelDock->setWidget(objectTree);
    objectTreePanelDock->setMaximumWidth(350);
    objectTreePanelDock->setMaximumHeight(200);
    addDockWidget(Qt::RightDockWidgetArea, objectTreePanelDock);

    QAction *viewObjectTreePanelAct = objectTreePanelDock->toggleViewAction();

    QAction *addSphereAct = new QAction(QString::fromUtf8("Nova esfera"), this);
    addSphereAct->setStatusTip(tr("Adicionar uma nova esfera a cena."));
    connect(addSphereAct, SIGNAL(triggered()), this, SLOT(addSphere()));

    deleteObjectAct = new QAction(QString::fromUtf8("Deletar objeto"), this);
    deleteObjectAct->setShortcuts(QKeySequence::Delete);
    deleteObjectAct->setEnabled(false);
    deleteObjectAct->setStatusTip(QString::fromUtf8("Deletar objetos selecionados."));
    connect(deleteObjectAct, SIGNAL(triggered()), this, SLOT(deleteObject()));

    objectTree->addAction(addSphereAct);
    objectTree->addAction(deleteObjectAct);

    connect(objectTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(editObjectDialog(QTreeWidgetItem *, int)));
    connect(objectTree, SIGNAL(itemSelectionChanged()), this, SLOT(changeObjectsSelection()));




    QDockWidget *globalOptionsPanelDock = new QDockWidget(QString::fromUtf8("Opções globais"), this);

    globalOptionsPanel = new GlobalOptionsPanel(globalOptionsPanelDock);

    globalOptionsPanelDock->setWidget(globalOptionsPanel);
    globalOptionsPanelDock->setMaximumWidth(350);

    addDockWidget(Qt::RightDockWidgetArea, globalOptionsPanelDock);

    QAction *globalOptionsPanelAct = globalOptionsPanelDock->toggleViewAction();

    connect(globalOptionsPanel, SIGNAL(updateAdjacency()), this, SLOT(updateAdjacency()));
    connect(globalOptionsPanel, SIGNAL(updateGravity()), this, SLOT(updateGravity()));
    connect(globalOptionsPanel, SIGNAL(updateDeltaT()), this, SLOT(updateDeltaT()));



    QDockWidget *collisionOptionsPanelDock = new QDockWidget(QString::fromUtf8("Colisão"), this);

    collisionOptionsPanel = new CollisionOptionsPanel(collisionOptionsPanelDock);

    collisionOptionsPanelDock->setWidget(collisionOptionsPanel);
    collisionOptionsPanelDock->setMaximumWidth(350);

    addDockWidget(Qt::RightDockWidgetArea, collisionOptionsPanelDock);

    QAction *collisionOptionsPanelAct = collisionOptionsPanelDock->toggleViewAction();

    connect(collisionOptionsPanel, SIGNAL(updateDistanceError()), this, SLOT(updateDistanceError()));
    connect(collisionOptionsPanel, SIGNAL(updateDampingFactor()), this, SLOT(updateDampingFactor()));
    connect(collisionOptionsPanel, SIGNAL(updateActive()), this, SLOT(updateActiveCollision()));



    QDockWidget *airOptionsPanelDock = new QDockWidget(QString::fromUtf8("Ar"), this);

    airOptionsPanel = new AirOptionsPanel(airOptionsPanelDock);

    airOptionsPanelDock->setWidget(airOptionsPanel);
    airOptionsPanelDock->setMaximumWidth(350);

    addDockWidget(Qt::RightDockWidgetArea, airOptionsPanelDock);

    QAction *airOptionsPanelAct = airOptionsPanelDock->toggleViewAction();

    connect(airOptionsPanel, SIGNAL(updateViscosity()), this, SLOT(updateAirViscosity()));
    connect(airOptionsPanel, SIGNAL(updateDirection()), this, SLOT(updateAirDirection()));
    connect(airOptionsPanel, SIGNAL(updateMagnitude()), this, SLOT(updateAirDirection()));
    connect(airOptionsPanel, SIGNAL(updateType()), this, SLOT(updateAirType()));
    connect(airOptionsPanel, SIGNAL(updateActive()), this, SLOT(updateActiveAir()));

    methodsOptionsPanelDock = new QDockWidget(QString::fromUtf8("Método"), this);
    methodsOptionsPanelDock->hide();

    methodsOptionsPanel = new MethodsOptionsPanel(methodsOptionsPanelDock);

    methodsOptionsPanelDock->setWidget(methodsOptionsPanel);
    methodsOptionsPanelDock->setMaximumWidth(350);

    addDockWidget(Qt::RightDockWidgetArea, methodsOptionsPanelDock);

    QAction *methodsOptionsPanelAct = methodsOptionsPanelDock->toggleViewAction();

    connect(methodsOptionsPanel, SIGNAL(updateImplicitJacobiThreshold()), this, SLOT(updateImplicitJacobiThreshold()));
    connect(methodsOptionsPanel, SIGNAL(updateImplicitJacobiMaxIteration()), this, SLOT(updateImplicitJacobiMaxIteration()));
    connect(methodsOptionsPanel, SIGNAL(updateImplicitSORThreshold()), this, SLOT(updateImplicitSORThreshold()));
    connect(methodsOptionsPanel, SIGNAL(updateImplicitSORRelaxation()), this, SLOT(updateImplicitSORRelaxation()));
    connect(methodsOptionsPanel, SIGNAL(updateImplicitSORMaxIteration()), this, SLOT(updateImplicitSORMaxIteration()));
    connect(methodsOptionsPanel, SIGNAL(updateImprovedVerletEta()), this, SLOT(updateImprovedVerletEta()));



    tabifyDockWidget(airOptionsPanelDock, collisionOptionsPanelDock);
    tabifyDockWidget(collisionOptionsPanelDock, globalOptionsPanelDock);
    tabifyDockWidget(globalOptionsPanelDock, objectTreePanelDock);
    tabifyDockWidget(objectTreePanelDock, methodsOptionsPanelDock);



    //actions
    QAction *openAct = new QAction(QString::fromUtf8("Abrir"), this);
    openAct->setStatusTip(tr("Abrir um tecido."));
    openAct->setShortcuts(QKeySequence::Open);

    connect(openAct, SIGNAL(triggered()), this, SLOT(openCAFile()));

    QAction *importOBJAct = new QAction(QString::fromUtf8("Importar OBJ"), this);
    importOBJAct->setStatusTip(tr("Abrir um tecido em formato OBJ."));

    connect(importOBJAct, SIGNAL(triggered()), this, SLOT(importOBJFile()));

    QAction *openPlaybackSimulationAct = new QAction(QString::fromUtf8("Playback"), this);
    openPlaybackSimulationAct->setStatusTip(tr("Abrir um arquivo da gravação."));

    connect(openPlaybackSimulationAct, SIGNAL(triggered()), this, SLOT(playbackSimulation()));

    QAction *exitAct = new QAction(QString::fromUtf8("Sair"), this);
    exitAct->setStatusTip(QString::fromUtf8("Sair da aplicação."));
    exitAct->setShortcuts(QKeySequence::Quit);

    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));



    forwardEulerMethodAct = new QAction(QString::fromUtf8("Forward Euler"), this);
    forwardEulerMethodAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Forward Euler."));
    forwardEulerMethodAct->setCheckable(true);
    forwardEulerMethodAct->setChecked(true);

    connect(forwardEulerMethodAct, SIGNAL(triggered(bool)), this, SLOT(changeToForwardEulerMethod(bool)));

    midpointMethodAct = new QAction(QString::fromUtf8("Midpoint"), this);
    midpointMethodAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Midpoint."));
    midpointMethodAct->setCheckable(true);
    midpointMethodAct->setChecked(false);

    connect(midpointMethodAct, SIGNAL(triggered(bool)), this, SLOT(changeToMidpointMethod(bool)));

    rungeKuttaMethodAct = new QAction(QString::fromUtf8("Runge Kutta"), this);
    rungeKuttaMethodAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Runge Kutta."));
    rungeKuttaMethodAct->setCheckable(true);
    rungeKuttaMethodAct->setChecked(false);

    connect(rungeKuttaMethodAct, SIGNAL(triggered(bool)), this, SLOT(changeToRungeKuttaMethod(bool)));

    adaptiveRungeKuttaMethodAct = new QAction(QString::fromUtf8("Runge Kutta Adaptado"), this);
    adaptiveRungeKuttaMethodAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Runge Kutta adaptado por Wang 2009."));
    adaptiveRungeKuttaMethodAct->setCheckable(true);
    adaptiveRungeKuttaMethodAct->setChecked(false);

    connect(adaptiveRungeKuttaMethodAct, SIGNAL(triggered(bool)), this, SLOT(changeToAdaptiveRungeKuttaMethod(bool)));

    improvedVerletAct = new QAction(QString::fromUtf8("Verlet Modificado"), this);
    improvedVerletAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Verlet modificado por Jiang 2010."));
    improvedVerletAct->setCheckable(true);
    improvedVerletAct->setChecked(false);

    connect(improvedVerletAct, SIGNAL(triggered(bool)), this, SLOT(changeToImprovedVerlet(bool)));

    aproximatedImplicitAct = new QAction(QString::fromUtf8("Backward Euler Aproximado"), this);
    aproximatedImplicitAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo Backward Euler aproximado proposto por Kang 2000"));
    aproximatedImplicitAct->setCheckable(true);
    aproximatedImplicitAct->setChecked(false);

    connect(aproximatedImplicitAct, SIGNAL(triggered(bool)), this, SLOT(changeToAproximatedImplicit(bool)));

    implicitSORAct = new QAction(QString::fromUtf8("Backward Euler - SOR"), this);
    implicitSORAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo Backward Euler sendo o sistema resolvido pelo método SOR proposto por Jiang 2005"));
    implicitSORAct->setCheckable(true);
    implicitSORAct->setChecked(false);

    connect(implicitSORAct, SIGNAL(triggered(bool)), this, SLOT(changeToImplicitSOR(bool)));

    hybridIntegrationAct = new QAction(QString::fromUtf8("Hybrid Integration"), this);
    hybridIntegrationAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo hibrido proposto por Eberhardt 2000"));
    hybridIntegrationAct->setCheckable(true);
    hybridIntegrationAct->setChecked(false);

    connect(hybridIntegrationAct, SIGNAL(triggered(bool)), this, SLOT(changeToHybridIntegration(bool)));

    implicitJacobiAct = new QAction(QString::fromUtf8("Implicit Integration"), this);
    implicitJacobiAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo interativo proposto por Kang 2004"));
    implicitJacobiAct->setCheckable(true);
    implicitJacobiAct->setChecked(false);

    connect(implicitJacobiAct, SIGNAL(triggered(bool)), this, SLOT(changeToImplicitJacobi(bool)));

    aproximatedJacobiAct = new QAction(QString::fromUtf8("Aproximated Jacobi"), this);
    aproximatedJacobiAct->setStatusTip(QString::fromUtf8("Rodar o programa com o médodo de Jacobi com uma interação proposto por Kang 2004"));
    aproximatedJacobiAct->setCheckable(true);
    aproximatedJacobiAct->setChecked(false);

    connect(aproximatedJacobiAct, SIGNAL(triggered(bool)), this, SLOT(changeToAproximatedJacobi(bool)));


    QAction *wireframeAct = new QAction(QString::fromUtf8("Wireframe"), this);
    wireframeAct->setStatusTip(QString::fromUtf8("Vizualizar tecido em wireframe"));
    wireframeAct->setShortcut(Qt::Key_Space);
    wireframeAct->setCheckable(true);
    wireframeAct->setChecked(true);

    connect(wireframeAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeWireframe(bool)));

    QAction *showAxisAct = new QAction(QString::fromUtf8("Eixos"), this);
    showAxisAct->setStatusTip(QString::fromUtf8("Vizualizar os eixos"));
    showAxisAct->setCheckable(true);
    showAxisAct->setChecked(true);

    connect(showAxisAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeShowAxis(bool)));

    QAction *showGridAct = new QAction(QString::fromUtf8("Grade"), this);
    showGridAct->setStatusTip(QString::fromUtf8("Vizualizar a grade"));
    showGridAct->setCheckable(true);
    showGridAct->setChecked(true);

    connect(showGridAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeShowGrid(bool)));

    QAction *showFloorAct = new QAction(QString::fromUtf8("Chão"), this);
    showFloorAct->setStatusTip(QString::fromUtf8("Vizualizar a chão"));
    showFloorAct->setCheckable(true);
    showFloorAct->setChecked(false);

    connect(showFloorAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeShowFloor(bool)));

    QAction *showMastAct = new QAction(QString::fromUtf8("Mastro"), this);
    showMastAct->setStatusTip(QString::fromUtf8("Vizualizar a mastro"));
    showMastAct->setCheckable(true);
    showMastAct->setChecked(false);

    connect(showMastAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeShowMast(bool)));

    QAction *showNormalAct = new QAction(QString::fromUtf8("Normais"), this);
    showNormalAct->setStatusTip(QString::fromUtf8("Vizualizar normal do tecido"));
    showNormalAct->setCheckable(true);
    showNormalAct->setChecked(false);

    connect(showNormalAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeShowNormal(bool)));

    QAction *drawSmoothAct = new QAction(QString::fromUtf8("Smooth"), this);
    drawSmoothAct->setStatusTip(QString::fromUtf8("Vizualizar tecido em smooth"));
    drawSmoothAct->setCheckable(true);
    drawSmoothAct->setChecked(true);

    connect(drawSmoothAct, SIGNAL(triggered(bool)), glWidget, SLOT(changeDrawSmooth(bool)));

    startPauseAct = new QAction(QIcon("images/startPause.png"), QString::fromUtf8("&Início/Pausa"), this);
    startPauseAct->setStatusTip(QString::fromUtf8("Início/Pausa."));
    startPauseAct->setCheckable(true);
    startPauseAct->setChecked(false);

    connect(startPauseAct, SIGNAL(triggered(bool)), this, SLOT(startPauseSimulation(bool)));

    stopAct = new QAction(QIcon("images/stop.png"), tr("&Parar"), this);
    stopAct->setStatusTip(tr("Parar."));

    connect(stopAct, SIGNAL(triggered()), this, SLOT(stopSimulation()));

    restartAct = new QAction(QIcon("images/restart.png"), QString::fromUtf8("&Recomeçar"), this);
    restartAct->setStatusTip(QString::fromUtf8("Recomeçar."));

    connect(restartAct, SIGNAL(triggered()), glWidget, SLOT(restartSimulation()));

    recordAct = new QAction(QIcon("images/record.png"), QString::fromUtf8("&Gravar"), this);
    recordAct->setStatusTip(QString::fromUtf8("Gravar."));
    recordAct->setCheckable(true);
    recordAct->setChecked(false);

    connect(recordAct, SIGNAL(triggered(bool)), this, SLOT(recordSimulation(bool)));


    //menus
    QMenu *fileMenu = menuBar()->addMenu(QString::fromUtf8("&Arquivo"));

    fileMenu->addAction(openAct);
    fileMenu->addAction(importOBJAct);
    fileMenu->addSeparator();
    fileMenu->addAction(openPlaybackSimulationAct);
    fileMenu->addAction(exitAct);


    QMenu *viewMenu = menuBar()->addMenu(QString::fromUtf8("&Vizualização"));

    viewMenu->addAction(wireframeAct);
    viewMenu->addAction(showAxisAct);
    viewMenu->addAction(showGridAct);
    viewMenu->addAction(showFloorAct);
    viewMenu->addAction(showMastAct);
    viewMenu->addAction(showNormalAct);
    viewMenu->addAction(drawSmoothAct);
    viewMenu->addSeparator();
    viewMenu->addAction(viewFabricTreePanelAct);
    viewMenu->addAction(viewObjectTreePanelAct);
    viewMenu->addAction(globalOptionsPanelAct);
    viewMenu->addAction(collisionOptionsPanelAct);
    viewMenu->addAction(airOptionsPanelAct);
    viewMenu->addAction(methodsOptionsPanelAct);



    QMenu *methodMenu = menuBar()->addMenu(QString::fromUtf8("&Método"));

    methodMenu->addAction(forwardEulerMethodAct);
    methodMenu->addAction(midpointMethodAct);
    methodMenu->addAction(rungeKuttaMethodAct);
    methodMenu->addAction(adaptiveRungeKuttaMethodAct);
    methodMenu->addAction(improvedVerletAct);
    methodMenu->addAction(aproximatedImplicitAct);
    methodMenu->addAction(implicitSORAct);
    methodMenu->addAction(hybridIntegrationAct);
    methodMenu->addAction(implicitJacobiAct);
    methodMenu->addAction(aproximatedJacobiAct);



        //toolbar
    modeComboBox = new QComboBox;
    modeComboBox->addItem(QString::fromUtf8("Simulação"));
    modeComboBox->addItem(QString::fromUtf8("Reprodução"));
    connect(modeComboBox, SIGNAL(activated(int)), this, SLOT(changeMode(int)));

//      QPushButton *startButton = new QPushButton(tr("Comecar"),this);
//      connect(startButton, SIGNAL(clicked(bool)), this, SLOT(startSimulation(void)));
//
//      QPushButton *stopButton = new QPushButton(tr("Parar"),this);
//      connect(stopButton, SIGNAL(clicked(bool)), this, SLOT(stopSimulation(void)));
//
//      QPushButton *restartButton = new QPushButton(tr("Recomecar"),this);
//      connect(restartButton, SIGNAL(clicked(bool)), this, SLOT(restartSimulation(void)));
//
//      QCheckBox *recordCheckBox = new QCheckBox(tr("Gravar"));
//    recordCheckBox->setChecked(false);

//    QHBoxLayout *playLayout = new QHBoxLayout;
//    playLayout->addAction(startPauseAct);
////    playLayout->addWidget(stopAct);
//    playLayout->addWidget(restartAct);
//    playLayout->addWidget(recordAct);
//    playLayout->addStretch(1);



    QToolBar *modeToolBar = addToolBar(tr("Modo"));

    modeToolBar->addWidget(modeComboBox);
//    modeToolBar->addWidget(playWidget);
    modeToolBar->addAction(startPauseAct);
    modeToolBar->addAction(stopAct);
    modeToolBar->addAction(restartAct);
    modeToolBar->addAction(recordAct);
    changeMode(SIMULATION);
}

void Window::openFile(){
    if (fileName.isNull()) return;

    restartMode();
    startPauseSimulation(false);
    changeMode(SIMULATION);

    fabricTree->clear();

    QFile *file = new QFile(fileName);
    file->open(QFile::ReadOnly);

    std::vector<Fabric *> fabrics = glWidget->loadFile(file, method, globalOptionsPanel->getDeltaT(),
                                                       globalOptionsPanel->getGravity(), globalOptionsPanel->getAdjacency(),
                                                       collisionOptionsPanel->getActive(),
                                                       collisionOptionsPanel->getDampingFactor(),
                                                       collisionOptionsPanel->getDistanceError(),
                                                       airOptionsPanel->getActive(), airOptionsPanel->getType(),
                                                       airOptionsPanel->getPeriod(), airOptionsPanel->getRepeat(),
                                                       airOptionsPanel->getViscosity(), airOptionsPanel->getDirection()
                                                       );

    connect(glWidget->getSolver(), SIGNAL(pause(bool)), this, SLOT(startPauseSimulation(bool)));

    //colocando os tecidos na arvore
    QTreeWidgetItem *rootItem = fabricTree->invisibleRootItem();
    for(unsigned int i = 0; i < fabrics.size(); i++)
    {
        new FabricTreeItem(rootItem, fabrics[i]);
    }
}

void Window::openPlaybackFile(){
    if (playbackFileName.isNull()) return;

    startPauseSimulation(false);
    changeMode(PLAYBACK);

    fabricTree->clear();

    QFile *file = new QFile(playbackFileName);
    file->open(QFile::ReadOnly);
    std::vector<Fabric *> fabrics = glWidget->loadFile(file);

    //colocando os tecidos na arvore
    QTreeWidgetItem *rootItem = fabricTree->invisibleRootItem();
    for(unsigned int i = 0; i < fabrics.size(); i++)
    {
        new FabricTreeItem(rootItem, fabrics[i]);
    }
}

void Window::openCAFile(){
    fileName = QFileDialog::getOpenFileName(this, tr("Abrir arquivo"), QDir::currentPath(), tr("Clothani Files (*.ca)"));

    openFile();
}

void Window::importOBJFile(){
    fileName = QFileDialog::getOpenFileName(this, tr("Abrir arquivo"), QDir::currentPath(), tr("Object Files (*.obj)"));

    openFile();
}

void Window::playbackSimulation(){
    playbackFileName = QFileDialog::getOpenFileName(this, tr("Abrir arquivo"), QDir::currentPath(), tr("Object Files (*.sim)"));

    openPlaybackFile();
}

void Window::changeSolver()
{
    stopSimulation();
    changeMode(SIMULATION);

    Solver *s = glWidget->changeSolver(method, globalOptionsPanel->getDeltaT(), globalOptionsPanel->getGravity(),
                       collisionOptionsPanel->getActive(), collisionOptionsPanel->getDampingFactor(),
                       collisionOptionsPanel->getDistanceError(), airOptionsPanel->getActive(), airOptionsPanel->getType(),
                       airOptionsPanel->getPeriod(), airOptionsPanel->getRepeat(),
                       airOptionsPanel->getViscosity(), airOptionsPanel->getDirection()
                       );

    connect(s, SIGNAL(pause(bool)), this, SLOT(startPauseSimulation(bool)));
}

void Window::changeToForwardEulerMethod(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !forwardEulerMethodAct->isChecked()) _b = true;

    forwardEulerMethodAct->setChecked(_b);

    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = FORWARD_EULER;

    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToMidpointMethod(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !midpointMethodAct->isChecked()) _b = true;

    midpointMethodAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = MIDPOINT;

    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToRungeKuttaMethod(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !rungeKuttaMethodAct->isChecked()) _b = true;

    rungeKuttaMethodAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = RUNGE_KUTTA;

    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToAdaptiveRungeKuttaMethod(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !adaptiveRungeKuttaMethodAct->isChecked()) _b = true;

    adaptiveRungeKuttaMethodAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = ADAPTIVE_RUNGE_KUTTA;

    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToImprovedVerlet(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !improvedVerletAct->isChecked()) _b = true;

    improvedVerletAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = IMPROVED_VERLET;

    changeSolver();

    Solver *s = glWidget->getSolver();
    if(s) ((ImprovedVerlet *)s->getIntegrationMethod())->setEta(methodsOptionsPanel->getImprovedVerletEta());


    methodsOptionsPanelDock->show();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Método Improved Verlet"));
    methodsOptionsPanelDock->raise();
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToAproximatedImplicit(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !aproximatedImplicitAct->isChecked()) _b = true;

    aproximatedImplicitAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = APROXIMATED_IMPLICIT;


    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToImplicitSOR(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && !implicitSORAct->isChecked()) _b = true;

    implicitSORAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = IMPLICIT_SOR;


    changeSolver();

    Solver *s = glWidget->getSolver();
    if(s)
    {
        ((ImplicitSOR *)s->getIntegrationMethod())->setThreshold(methodsOptionsPanel->getImplicitSORThreshold());
        ((ImplicitSOR *)s->getIntegrationMethod())->setRelaxation(methodsOptionsPanel->getImplicitSORRelaxation());
        ((ImplicitSOR *)s->getIntegrationMethod())->setMaxIteration(methodsOptionsPanel->getImplicitSORMaxIteration());
    }

    methodsOptionsPanelDock->show();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Método Implicit SOR"));
    methodsOptionsPanelDock->raise();
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToHybridIntegration(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && ! hybridIntegrationAct->isChecked()) _b = true;

    hybridIntegrationAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);




    if(_b) method = HYBRID_INTEGRATION;


    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::changeToImplicitJacobi(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && ! implicitJacobiAct->isChecked()) _b = true;

    implicitJacobiAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    aproximatedJacobiAct->setChecked(!_b);



    if(_b) method = IMPLICIT_JACOBI;


    changeSolver();

    Solver *s = glWidget->getSolver();
    if(s)
    {
        ((ImplicitJacobi *)s->getIntegrationMethod())->setThreshold(methodsOptionsPanel->getImplicitJacobiThreshold());
        ((ImplicitJacobi *)s->getIntegrationMethod())->setMaxIteration(methodsOptionsPanel->getImplicitJacobiMaxIteration());
    }

    methodsOptionsPanelDock->show();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Método Implicit Jacobi"));
    methodsOptionsPanelDock->raise();
    methodsOptionsPanel->changeLayout(method);
}


void Window::changeToAproximatedJacobi(bool _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado
    if(!_b && ! aproximatedJacobiAct->isChecked()) _b = true;

    aproximatedJacobiAct->setChecked(_b);

    forwardEulerMethodAct->setChecked(!_b);
    midpointMethodAct->setChecked(!_b);
    rungeKuttaMethodAct->setChecked(!_b);
    adaptiveRungeKuttaMethodAct->setChecked(!_b);
    improvedVerletAct->setChecked(!_b);
    aproximatedImplicitAct->setChecked(!_b);
    implicitSORAct->setChecked(!_b);
    hybridIntegrationAct->setChecked(!_b);
    implicitJacobiAct->setChecked(!_b);


    if(_b) method = APROXIMATED_JACOBI;


    changeSolver();

    methodsOptionsPanelDock->hide();
    methodsOptionsPanelDock->setWindowTitle(QString::fromUtf8("Métodos"));
    methodsOptionsPanel->changeLayout(method);
}

void Window::restartMode(){
    startPauseSimulation(false);
    recordSimulation(false);
}

void Window::changeMode(int _b){
    //se só existia ele selecionado, e ele acabou de ser descelecionado ele volta a ser selecionado

    bool option = (_b == SIMULATION);
    recordAct->setVisible(option);
    glWidget->changeDrawPlayback(!option);

    if(mode != _b){
        restartMode();
        glWidget->stopSimulation();

        fabricTree->clear();

        if(option){
            std::vector<Fabric *> fabrics;
            fabrics = glWidget->getFabrics();

            //colocando os tecidos na arvore
            QTreeWidgetItem *rootItem = fabricTree->invisibleRootItem();
            for(unsigned int i = 0; i < fabrics.size(); i++)
            {
                new FabricTreeItem(rootItem, fabrics[i]);
            }
        }
        else{
            std::vector<Fabric *> *fabrics;
            fabrics = glWidget->getPlaybackFabrics();
            if(!fabrics) return;

            //colocando os tecidos na arvore
            QTreeWidgetItem *rootItem = fabricTree->invisibleRootItem();
            for(unsigned int i = 0; i < fabrics->size(); i++)
            {
                new FabricTreeItem(rootItem, fabrics->at(i));
            }
        }

    }

    mode = _b;
    modeComboBox->setCurrentIndex(mode);

    startPauseAct->setVisible(true);
    stopAct->setVisible(true);
    restartAct->setVisible(true);
}

void Window::startPauseSimulation(bool _b){
//    if(mode == SIMULATION){
    if(!glWidget->startPauseSimulation(_b))
        startPauseAct->setChecked(false);
//    }
}

void Window::stopSimulation(){
    startPauseAct->setChecked(false);
    glWidget->stopSimulation();
    if(mode == SIMULATION){
        recordSimulation(false);
    }
}

void Window::recordSimulation(bool _b){
    recordAct->setChecked(_b);
    if (_b){
        bool checked = startPauseAct->isChecked();

        if(checked) glWidget->startPauseSimulation(false);

        playbackFileName = QFileDialog::getSaveFileName(this, QString::fromUtf8("Salvar simulação"), QDir::currentPath(), QString::fromUtf8("Arquivo de simulação (*.sim)"));

        if (playbackFileName.isEmpty()){
            glWidget->recordSimulation(!_b);
            recordAct->setChecked(false);
        }

        if (QFileInfo(playbackFileName).suffix().isEmpty())
            playbackFileName += ".sim";

        QFile* file = new QFile(playbackFileName);
        file->open(QFile::WriteOnly);
        glWidget->recordSimulation(_b, file);

        if(checked) glWidget->startPauseSimulation(true);
    }else{
        glWidget->recordSimulation(_b);
    }
}

void Window::updateAdjacency()
{
    std::cout << "---------------------------------------------------\n\tEle vai reabrir o arquivo com a adjacencia modificada?\n\tOu só irá funcionar para quandoa brir o arquivo novamente de outra maneira?\n---------------------------------------------------"<<std::endl;
}

void Window::updateGravity()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setGravity(globalOptionsPanel->getGravity());
}

void Window::updateDeltaT()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setDeltaT(globalOptionsPanel->getDeltaT());
}

void Window::updateActiveCollision()
{
    Solver *s = glWidget->getSolver();
    if(s) s->setActiveCollision(collisionOptionsPanel->getActive());
}

void Window::updateDistanceError()
{
    Solver *s = glWidget->getSolver();
    if(s) s->setDistanceError(collisionOptionsPanel->getDistanceError());
}

void Window::updateDampingFactor()
{
    Solver *s = glWidget->getSolver();
    if(s) s->setDampingFactor(collisionOptionsPanel->getDampingFactor());
}

void Window::updateActiveAir()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setActiveAir(airOptionsPanel->getActive());
}

void Window::updateAirType()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setAirType(airOptionsPanel->getType());
}

void Window::updateAirDirection()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setAirDirection(airOptionsPanel->getDirection());
}

void Window::updateAirViscosity()
{
    Solver *s = glWidget->getSolver();
    if(s) s->getIntegrationMethod()->setAirViscosity(airOptionsPanel->getViscosity());
}

void Window::updateImplicitJacobiThreshold()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImplicitJacobi *)s->getIntegrationMethod())->setThreshold(methodsOptionsPanel->getImplicitJacobiThreshold());
}

void Window::updateImplicitJacobiMaxIteration()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImplicitJacobi *)s->getIntegrationMethod())->setMaxIteration(methodsOptionsPanel->getImplicitJacobiMaxIteration());
}

void Window::updateImplicitSORThreshold()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImplicitSOR *)s->getIntegrationMethod())->setThreshold(methodsOptionsPanel->getImplicitSORThreshold());
}

void Window::updateImplicitSORRelaxation()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImplicitSOR *)s->getIntegrationMethod())->setRelaxation(methodsOptionsPanel->getImplicitSORRelaxation());
}

void Window::updateImplicitSORMaxIteration()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImplicitSOR *)s->getIntegrationMethod())->setMaxIteration(methodsOptionsPanel->getImplicitSORMaxIteration());
}

void Window::updateImprovedVerletEta()
{
    //assume-se que o método é o correto
    Solver *s = glWidget->getSolver();
    if(s) ((ImprovedVerlet *)s->getIntegrationMethod())->setEta(methodsOptionsPanel->getImprovedVerletEta());
}

void Window::addObject(Object *_obj)
{
    glWidget->addObject(_obj);

    QTreeWidgetItem *rootItem = objectTree->invisibleRootItem();
    new ObjectTreeItem(rootItem, _obj);
}

void Window::deleteObject(){
//    startPauseSimulation(false);
    objectInOperation = true;
    ObjectTreeItem *item = NULL;

    for(int i = previousSelectedObjects.size(); i > 0 ; i--)
    {
        item = (ObjectTreeItem *)previousSelectedObjects[i-1];

        Object *obj = item->getObject();
        glWidget->deleteObject(obj);
        previousSelectedObjects.erase(previousSelectedObjects.begin() + i - 1);

        delete item;
    }

    objectInOperation = false;
    updateActions();
}

void Window::deleteFabric(){
    startPauseSimulation(false);
    recordSimulation(false);
    fabricInOperation = true;
    FabricTreeItem *item = NULL;

    for(int i = previousSelectedFabrics.size(); i > 0 ; i--)
    {
        item = (FabricTreeItem *)previousSelectedFabrics[i-1];

        Fabric *obj = item->getFabric();
        glWidget->deleteFabric(obj);
        previousSelectedFabrics.erase(previousSelectedFabrics.begin() + i - 1);

        delete item;
    }

    fabricInOperation = false;
    updateActions();
}

void Window::editObjectDialog(QTreeWidgetItem *_item, int )
{
    Object *obj = ((ObjectTreeItem *)_item)->getObject();

    switch(obj->getType()){
        case SPHERE:{
            SphereDialog *dlg = new SphereDialog((ObjectTreeItem *)_item, this);
            dlg->show();

//            connect(dlg, SIGNAL(done()), (ObjectTreeItem *)_item, SLOT(update()));
            connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
            break;
        }
    }
}

void Window::editFabricDialog(QTreeWidgetItem *_item, int)
{
    unsigned int type = ((TreeItem *)_item)->getType();

    switch(type){
        case FABRIC:{
            FabricDialog *dlg = new FabricDialog((FabricTreeItem *)_item, this);
            dlg->show();

            connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
            break;
        }
        case INFO:{
            if( ((TreeItem *)(_item->parent()))->getType() == FABRIC )
            {
                unsigned int childType = ((TreeItem *)(_item->child(0)))->getType();
                if( childType == PARTICLE )
                {
                    ParticlesDialog *dlg = new ParticlesDialog((TreeItem *)_item, this);
                    dlg->show();

                    connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
                }else if( childType == SPRING )
                {
                    SpringsDialog *dlg = new SpringsDialog((TreeItem *)_item, this);
                    dlg->show();

                    connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
                }
            }
            break;
        }
        case PARTICLE:{
            ParticleDialog *dlg = new ParticleDialog((ParticleTreeItem *)_item, this);
            dlg->show();

            connect(dlg, SIGNAL(startPauseSimulation(bool)), glWidget, SLOT(startPauseSimulation(bool)));
            connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
            break;
        }
        case SPRING:{
            SpringDialog *dlg = new SpringDialog((SpringTreeItem *)_item, this);
            dlg->show();

            connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
            break;
        }
    }
}

void Window::addSphere()
{
    SphereDialog *dlg = new SphereDialog(objectId++, this);
    dlg->show();

    connect(dlg, SIGNAL(done(Object *)), this, SLOT(addObject(Object *)));
    connect(dlg, SIGNAL(done()), glWidget, SLOT(updateGL()));
}

void Window::updateActions()
{
    deleteObjectAct->setEnabled(!previousSelectedObjects.empty());

    deleteFabricAct->setEnabled(false);
    if(!previousSelectedFabrics.empty())
    {
        //só deixa ser usado se fabric tiver selecionado
        QTreeWidgetItem *item = previousSelectedFabrics.front();
        if( ((TreeItem *)item)->getType() == FABRIC )
            deleteFabricAct->setEnabled(true);
    }

}

void Window::changeObjectsSelection()
{
    if(objectInOperation) return;

    objectInOperation = true;

    QList<QTreeWidgetItem *> selected = objectTree->selectedItems();


    //descelecionando os anteriores
    for(int i = 0; i < previousSelectedObjects.size(); i++){
        QTreeWidgetItem *item = previousSelectedObjects.at(i);
        ((TreeItem *)item)->select(false);
    }
    previousSelectedObjects.clear();

    //selecionando de fato os novos
    for(int i = 0; i < selected.size(); i++){
        QTreeWidgetItem *item = selected.at(i);
        ((TreeItem *)item)->select(true);
        previousSelectedObjects.push_back(item);
    }

    updateActions();

    objectInOperation = false;
}

void Window::changeFabricsSelection()
{
    if(fabricInOperation) return;

    fabricInOperation = true;

    QList<QTreeWidgetItem *> selected = fabricTree->selectedItems();


    //descelecionando os anteriores
    for(int i = 0; i < previousSelectedFabrics.size(); i++){
        QTreeWidgetItem *item = previousSelectedFabrics.at(i);
        ((TreeItem *)item)->select(false);
    }
    previousSelectedFabrics.clear();

    //selecionando de fato os novos
    //só serão selecionados os item do mesmo tipo
    if(!selected.empty())
    {
        QTreeWidgetItem *front = selected.front();
        unsigned int type = ((TreeItem *)front)->getType();
        if(type == INFO)
        {
            for(int i = 0; i < front->childCount(); i++){
                QTreeWidgetItem *item = front->child(i);
                ((TreeItem *)item)->select(true);
                previousSelectedFabrics.push_back(item);
            }

            for(int i = 1; i < selected.size(); i++){
                QTreeWidgetItem *item = selected.at(i);
                item->setSelected(false);
            }
        }
        else
        {
            for(int i = 0; i < selected.size(); i++){
                QTreeWidgetItem *item = selected.at(i);
                if( ((TreeItem *)item)->getType() == type)
                {
                    ((TreeItem *)item)->select(true);
                    previousSelectedFabrics.push_back(item);
                }
                else
                {
                    item->setSelected(false);
                }
            }
        }
    }

    updateActions();
    fabricInOperation = false;
}
